const path = require('path');

process.env.LOG_FILENAME = path.join(__dirname, 'parse');

const fs = require('fs');
const fsPromise = fs.promises;
const { Client } = require('ssh2');
const _ = require("lodash");
const spark = require(`${process.env.SPARK_HOME}/ecma/spark`);
const RTable = spark.spark.RTable;

const { _writeHistory, _writeEvent } = require('../src/influx');
const { logger } = require('../src/logging');
const { sleep } = require('../src/util');

const RELAY_SERVER = {
  host: '106.14.253.154',
  port: 22,
  username: 'root',
  privateKey: fs.readFileSync(`${process.env.HOME}/.ssh/id_rsa`)	 // 使用gong钥登录，每台机器的.ssh/id_rsa的内容不同
};
const WORKDIR = 'rkt';
const LOCAL_FILE = path.join(__dirname, '.downlod.json');

const scada_signal = new RTable('scada_signal');
const scada_equip = new RTable('scada_equip');
let first_time = true;
const signalMap = buildSignalMap();
// logger.info('signalMap: ' + JSON.stringify(signalMap));

function buildSignalMap() {
  const map = {};
  const signals = scada_signal.list();
  for (let s of signals) {
    const equip = scada_equip.find(s.equip);
    s.equip_desc = equip.describe;
    // s.bay = equip.bay;
    // s.substation = equip.substation;
    map[s.name] = s;
  }
  return map;
}

async function processJsonData(data) {
  const { analog, signal, ts } = data; // ts:毫秒时间戳,导出数据时候的时间
  logger.debug('processJsonData: ' + ts);

  const values = [];
  const events = [];
  
  // 处理模拟量数据
  for (const name in analog) {
    const v = analog[name];
    try {
      spark.setAnalog(name, v);
    } catch (err) {
      logger.warn(`analog ${name} set faiil ${err}`);
    }
    values.push({ id: name, value: v, raw: v, quality: 1, clazz: '0', partition: '0', time: ts });
  }

  // 处理遥信数据
  for (const name in signal) {
    const v = signal[name];
    try {
      spark.setSignal(name, v);
    } catch (err) {
      logger.warn(`signal ${name} set faiil ${err}`);
    }
    values.push({ id: name, value: v, raw: v, quality: 1, clazz: '0', partition: '0', time: ts });
    
    // 检测遥信值是否发生变化
    const signal_pt = signalMap[name];
    if (!signal_pt) continue;
    if (signal_pt.value !== v) {
      signal_pt.value = v;
      if (!first_time) {
        events.push({
          value: v,                    // 值
          member0: name,             // 测点NAME
          member1: signal_pt.equip,              // 一次设备ID
          member2: signal_pt.bay,               // 间隔ID
          member3: signal_pt.substation,               // 厂站ID
          text: `${signal_pt.equip_desc} ${signal_pt.describe} ${v ? '动作': '复位'}`, // 文本描述
          type: 2007,                 // 类型
          almlevel: signal_pt.level,              // 告警等级
          time: ts                   // 毫秒时间戳
        });
      }
    }
  }
  first_time = false;

  if (!_.isEmpty(values)) {
    logger.info(`write ${values.length} values`);
    await _writeHistory(values);
  }
  if (!_.isEmpty(events)) {
    logger.info(`write ${events.length} events`);
    await _writeEvent(events);
  }
}

const conn = new Client();
let sftp;
let _running = true;

['SIGTERM', 'SIGINT', 'SIGHUP', 'SIGPIPE'].forEach(s => {
  process.on(s, (signal) => {
    logger.info('Exit with signal ' + signal);
    _running = false;
    // conn.end();
    // process.exit(1);
  });
});

function lsDir(location) {
  return new Promise((resolve, reject) => {
    sftp.readdir(location, (err, list) => {
      if (err) {
        reject(err);
        return;
      }

      const files = list.map(f => f.filename);
      resolve(files);
    });
  });
}

function download(remotePath, localPath) {
  return new Promise((resolve, reject) => {
    sftp.fastGet(remotePath, localPath, (err) => {
      if (err) {
        reject(err);
        return;
      }

      resolve();
    });
  });
}

function execCmd(command) {
  logger.debug('Exec: ' + command);
  return new Promise((resolve, reject) => {
    conn.exec(command, (err, stream) => {
      if (err) {
        reject(err);
        return;
      }

      stream.on('close', (code, signal) => {
        logger.debug('Stream :: close :: code: ' + code + ', signal: ' + signal);
        resolve(code);
      }).on('data', (data) => {
        logger.debug('STDOUT: ' + data);
      }).stderr.on('data', (data) => {
        logger.debug('STDERR: ' + data);
      });
    });
  });
}

async function loop() {

  logger.info('start loop');
  while (_running) {

    try {
      const files = await lsDir(WORKDIR);
      logger.debug('ls files ' + JSON.stringify(files));

      const jsonfiles = files.filter(f => f.endsWith('.json')).sort();
      if (_.isEmpty(jsonfiles)) {
        await sleep(1000);
        continue;
      }

      for (const f of jsonfiles) {
        await download(path.join(WORKDIR, f), LOCAL_FILE);   // 是远方的文件下载到localFile --y

        const str = await fsPromise.readFile(LOCAL_FILE, 'utf8');
        const data = JSON.parse(str);   //init files --json
        await processJsonData(data);
      }

      await execCmd(`rm ${jsonfiles.map(f => path.join(WORKDIR, f)).join(' ')}`);
    } catch (err) {
      logger.error('loop fail. ', err);
    }
  }
  logger.info('end loop');
}

conn.on('ready', () => {
  logger.info('Client :: ready');
  conn.sftp(async (err, sftpClient) => {
    if (err) throw err;

    sftp = sftpClient;
    await loop();
    conn.end();
  });
}).on('error', (err) => {
  logger.error('SSH连接错误: ' + err);
}).on('end', () => {
  logger.info('SSH连接已关闭');
}).connect(RELAY_SERVER);
